# 引入必要的库
# TODO
import yaml
import cv2 as cv
import time
import joblib
import os
import numpy as np
from skimage import io, feature
from tensorflow.keras.applications.vgg16 import VGG16, preprocess_input
from tensorflow.keras.preprocessing import image


# 获取 0_setting.yaml 中的键 key 对应的值 value
def get(key):
    # TODO
    with open("0_setting.yaml", "r", encoding='utf-8') as f:
        config = yaml.safe_load(f)
        value = config[key]
    return value


# 预处理图像, 把图像设置为指定大小之后，展平返回
def preprocess_image1(file_name, new_size):
    # 1. 读取图像灰度图
    # TODO
    img = cv.imread(file_name, 0)
    # 2. 调整图像大小为 new_size
    # TODO
    img = cv.resize(img, new_size)
    # 3. 将图像展平为一维数组
    # TODO
    img = img.ravel()
    return img


# 预处理图像(HOG), 把图像处理后获取特征向量，展平返回
def preprocess_image2(file_name, new_size):
    # 1. 读取图像灰度图
    # TODO
    img = io.imread(file_name, as_gray=True)
    img = cv.resize(img, new_size)
    # 2. 计算HOG特征
    # TODO
    hog_vec = feature.hog(img, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), visualize=False)
    # 3. 将图像展平为一维数组
    # TODO
    img = hog_vec.ravel()
    return img


# 预处理图像(VGG16), 把图像设置为指定大小之后，展平返回
def preprocess_image3(file_name, new_size):
    # 1. 使用keras内置的读图程序，以224x224的尺寸读取图像文件，结果为一个PIL图像对象
    # TODO
    img = image.load_img(file_name, target_size=new_size)
    # 2. 将PIL图像对象转换为NumPy数组
    img = image.img_to_array(img)
    # 3. 把单幅图像放到一个数组中，虽然只有一幅图像，但是我们仍然需要扩展数组的维度，以适应VGG16模型的输入尺寸要求（模型要求输入为4D张量）
    X = np.array([img])
    # 4. 使用VGG16模型的预处理函数对图像进行预处理，该步骤包括颜色空间的转换、缩放等
    X = preprocess_input(X)
    model = VGG16(weights='imagenet', include_top=False, pooling="max")
    # 5. 使用 VGG16 模型对图像进行特征提取，model.predict(X) 返回一个包含特征向量的数组
    # [0] 表示我们只提取第一张图像的特征向量，因为我们只输入了一张图像
    y = model.predict(X)[0].ravel()
    return y


# 用joblib把叫做 name 的对象 obj 保存(序列化)到位置 loc
def dump(obj, name, loc):
    start = time.time()
    print(f"把{name}保存到{loc}")
    # TODO 此处序列化对象
    joblib.dump(obj, loc)
    end = time.time()
    print(f"保存完毕,文件位置:{loc}, 大小:{os.path.getsize(loc) / 1024 / 1024:.3f}M")
    print(f"运行时间:{end - start:.3f}秒")


# 用joblib读取(反序列化)位置loc的对象obj,对象名为name
def load(name, loc):
    print(f"从{loc}提取文件{name}")
    # TODO 此处反序列化对象
    obj = joblib.load(loc)
    return obj
